/*
 * Copyright (C) 2013 Manuel Peinado
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.pla.lib.view.adapter;

import java.util.ArrayList;
import java.util.List;

import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.Checkable;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ListAdapter;

import com.pla.lib.view.PLA_AdapterView;
import com.pla.lib.view.PLA_AdapterView.OnItemClickListener;
import com.pla.lib.view.PLA_AdapterView.OnItemLongClickListener;
import com.pla.lib.view.listener.EnterMultiChoiceListener;
import com.pla.lib.view.listener.ItemClickInActionModePolicy;

class PLAMultiChoiceAdapterHelper implements OnItemLongClickListener, OnItemClickListener, OnCheckedChangeListener {
	private static final String BUNDLE_KEY = "mca__selection";
	private List<Object> checkedItems = new ArrayList<Object>();
	private PLA_AdapterView<? super ListAdapter> adapterView;
	private BaseAdapter owner;
	private OnItemClickListener itemClickListener;
	private OnItemLongClickListener itemLongClicklistener;
	private Boolean itemIncludesCheckBox;
	private EnterMultiChoiceListener listener;
	/*
	 * Defines what happens when an item is clicked and the action mode was already active
	 */
	private ItemClickInActionModePolicy itemClickInActionModePolicy = null;

	PLAMultiChoiceAdapterHelper(BaseAdapter owner) {
		this.owner = owner;
	}

	void restoreSelectionFromSavedInstanceState(Bundle savedInstanceState) {
		if (savedInstanceState == null) {
			return;
		}
		Object[] array = (Object[]) savedInstanceState.getSerializable(BUNDLE_KEY);
		checkedItems.clear();
		for (Object id : array) {
			checkedItems.add(id);
		}
	}

	void setAdapterView(PLA_AdapterView<? super ListAdapter> adapterView) {
		this.adapterView = adapterView;
		checkActivity();
		adapterView.setOnItemLongClickListener(this);
		adapterView.setOnItemClickListener(this);
		adapterView.setAdapter(owner);

		if (itemClickInActionModePolicy == null) {
			itemClickInActionModePolicy = ItemClickInActionModePolicy.OPEN;
		}
	}

	void checkActivity() {
		Context context = adapterView.getContext();
		if (context instanceof ListActivity) {
			throw new RuntimeException("ListView cannot belong to an activity which subclasses ListActivity");
		}
	}

	void setOnItemClickListener(OnItemClickListener listener) {
		this.itemClickListener = listener;
	}

	void save(Bundle outState) {
		Object[] array = new Object[checkedItems.size()];
		int i = 0;
		for (Object id : checkedItems) {
			array[i++] = id;
		}
		outState.putSerializable(BUNDLE_KEY, array);
	}

	void setItemChecked(Object handle, boolean checked) {
		if (checked) {
			checkItem(handle);
		} else {
			uncheckItem(handle);
		}
	}

	void checkItem(Object handle) {
		boolean wasSelected = isChecked(handle);
		if (wasSelected) {
			return;
		}
		checkedItems.add(handle);
		if (listener != null) {
			listener.checkItemCallback(getCheckedItemCount(), handle, true);
		}
		owner.notifyDataSetChanged();
	}

	void uncheckItem(Object handle) {
		boolean wasSelected = isChecked(handle);
		if (!wasSelected) {
			return;
		}
		checkedItems.remove(handle);
		if (listener != null) {
			listener.checkItemCallback(getCheckedItemCount(), handle, false);
		}
		if (getCheckedItemCount() == 0) {
			itemClickInActionModePolicy = ItemClickInActionModePolicy.OPEN;
			if (listener != null) {
				listener.exitMultiChoiceModel();
			}
		}
		owner.notifyDataSetChanged();
	}

	List<Object> getCheckedItems() {
		// Return a copy to prevent concurrent modification problems
		return new ArrayList<Object>(checkedItems);
	}

	int getCheckedItemCount() {
		return checkedItems.size();
	}

	boolean isChecked(Object handle) {
		return checkedItems.contains(handle);
	}

	Context getContext() {
		return adapterView.getContext();
	}

	void setItemClickInActionModePolicy(ItemClickInActionModePolicy policy) {
		itemClickInActionModePolicy = policy;
		switch (itemClickInActionModePolicy) {
		case OPEN:
			cancelAllSeleted();
			if (listener != null) {
				listener.exitMultiChoiceModel();
			}
			break;
		case SELECT:
			enterMultichoiceModel();
			break;
		}
	}

	/**
	 * 当进入多选模式时回调
	 */
	private void enterMultichoiceModel() {
		// TODO 添加震动
		if (listener != null) {
			listener.enterMultiChoiceModel();
		}
	}

	ItemClickInActionModePolicy getItemClickInActionModePolicy() {
		return itemClickInActionModePolicy;
	}

	View getView(Object position, View viewWithoutSelection) {
		int location = Integer.valueOf(position.toString());
		Object obj = adapterView.getItemAtPosition(location);
		if (viewWithoutSelection instanceof Checkable) {
			boolean selected = isChecked(obj);
			((Checkable) viewWithoutSelection).setChecked(selected);
		}
		if (itemIncludesCheckBox(viewWithoutSelection)) {
			initItemCheckbox(obj, (ViewGroup) viewWithoutSelection);
		}
		isChildChecked(viewWithoutSelection, obj);
		return viewWithoutSelection;
	}

	private void isChildChecked(View viewWithoutSelection, Object obj) {
		if (viewWithoutSelection instanceof ViewGroup) {
			ViewGroup root = (ViewGroup) viewWithoutSelection;
			for (int i = 0; i < root.getChildCount(); i++) {
				View child = root.getChildAt(i);
				if (child instanceof Checkable) {
					boolean selected = isChecked(obj);
					((Checkable) child).setChecked(selected);
				} else {
					isChildChecked(child, obj);
				}
			}
		}
	}

	private boolean itemIncludesCheckBox(View v) {
		if (itemIncludesCheckBox == null) {
			if (!(v instanceof ViewGroup)) {
				itemIncludesCheckBox = false;
			} else {
				ViewGroup root = (ViewGroup) v;
				itemIncludesCheckBox = root.findViewById(android.R.id.checkbox) != null;
			}
		}
		return itemIncludesCheckBox;
	}

	private void initItemCheckbox(Object position, ViewGroup view) {
		CheckBox checkBox = (CheckBox) view.findViewById(android.R.id.checkbox);
		boolean selected = isChecked(position);
		checkBox.setTag(position);
		checkBox.setChecked(selected);
		checkBox.setOnCheckedChangeListener(this);
	}

	@Override
	public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
		Object position = (Object) buttonView.getTag();
		setItemChecked(position, isChecked);
	}

	/**
	 * 退出多选模式并清空所有选择数据
	 */
	public void cancelAllSeleted() {
		checkedItems.clear();
		owner.notifyDataSetChanged();
	}

	/**
	 * 注册多选模式监听器
	 * 
	 * @param listener
	 *            监听器
	 */
	public void registerMultiChoiceListener(EnterMultiChoiceListener listener) {
		this.listener = listener;
	}

	/**
	 * 删除指定下标的选中状态
	 * 
	 * @param id
	 */
	public void removeCheckState(Object id) {
		uncheckItem(id);
	}

	@Override
	public void onItemClick(PLA_AdapterView<?> parent, View view, int position, long id) {
		switch (itemClickInActionModePolicy) {
		case SELECT:
			onItemLongClick(adapterView, view, position, id);
			return;
		case OPEN:
			if (itemClickListener != null) {
				itemClickListener.onItemClick(adapterView, view, position, id);
			}
			break;
		default:
			throw new RuntimeException("Invalid \"itemClickInActionMode\" value: " + itemClickInActionModePolicy);
		}
	}

	@Override
	public boolean onItemLongClick(PLA_AdapterView<?> parent, View view, int position, long id) {
		switch (itemClickInActionModePolicy) {
		case OPEN:
			itemClickInActionModePolicy = ItemClickInActionModePolicy.SELECT;
			enterMultichoiceModel();
			break;
		case SELECT:
			break;
		default:
			break;
		}
		Object obj = adapterView.getItemAtPosition(position);
		boolean wasChecked = isChecked(obj);
		setItemChecked(obj, !wasChecked);

		if (itemLongClicklistener != null) {
			return itemLongClicklistener.onItemLongClick(parent, view, position, id);
		}
		return true;
	}

	public void setOnItemLongClickListener(OnItemLongClickListener listener) {
		this.itemLongClicklistener = listener;
	}

	public void setCheckedItems(List<? extends Object> items) {
		checkedItems.clear();
		checkedItems.addAll(items);
	}
}
